#pragma once
#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>

static const int defaultSize = 6;

template <class T>
class RingQueue
{
    void P(sem_t& sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t& sem)
    {
        sem_post(&sem);
    }
    void lock(pthread_mutex_t& mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void unlock(pthread_mutex_t& mutex)
    {
        pthread_mutex_unlock(&mutex);
    }
public:
    RingQueue(int capacity = defaultSize)
        :_ring_queue(capacity), _capacity(capacity), _productor_step(0), _consumer_step(0)
    {
        sem_init(&_productor_sem, 0, _capacity);
        sem_init(&_consumer_sem, 0, 0);
        pthread_mutex_init(&_productor_mutex, nullptr);
        pthread_mutex_init(&_consumer_mutex, nullptr);

    }
    void EnQueue(const T& t)
    {
        P(_productor_sem);
        lock(_productor_mutex);

        _ring_queue[_productor_step++] = t;
        _productor_step %= _capacity;

        unlock(_productor_mutex);
        V(_consumer_sem);
    }
    void DeQueue(T& t)
    {
        P(_consumer_sem);
        lock(_consumer_mutex);
        
        t = _ring_queue[_consumer_step++];
        _consumer_step %= _capacity;

        unlock(_consumer_mutex);
        V(_productor_sem);
    }

    ~RingQueue()
    {
        sem_destroy(&_productor_sem);
        sem_destroy(&_consumer_sem);
        pthread_mutex_destroy(&_productor_mutex);
        pthread_mutex_destroy(&_consumer_mutex);
    }
private:
    //1.环形队列
    std::vector<T> _ring_queue;
    int _capacity;

    int _productor_step;
    int _consumer_step;

    sem_t _productor_sem;
    sem_t _consumer_sem;

    pthread_mutex_t _productor_mutex;
    pthread_mutex_t _consumer_mutex;
};